#include "List.h"
#include <iostream>
#include <fstream>

List::List() :m_size(0)
{
	/*������������ Head, Tail � m_size*/
	Head.pNext = &Tail;
	Tail.pPrev = &Head;
}

List::List(const List& other) :m_size(other.m_size)
{
	Head.pNext = &Tail;
	Tail.pPrev = &Head;

	Node* pThis = Tail.pPrev;
	Node* pOther = other.Head.pNext;

	for (size_t i = 0; i < m_size; i++)
	{
		pThis = new Node(pThis, *(pOther->m_Data));
		pOther = pOther->pNext;
	}
}

List::List(List&& other) :m_size(other.m_size)
{
	if (m_size)
	{
		Head.pNext = other.Head.pNext;
		Tail.pPrev = other.Tail.pPrev;

		Head.pNext->pPrev = &Head;
		Tail.pPrev->pNext = &Tail;

		other.Head.pNext = &other.Tail;
		other.Tail.pPrev = &other.Head;
		other.m_size = 0;
	}
	else
	{
		Head.pNext = &Tail;
		Tail.pPrev = &Head;
	}
}

List::~List()
{
	this->Remove_list();
}

void List::Ad_to(TO to, const Shape& shape)
{
	Node* Prev = nullptr;

	switch (to)
	{
	case List::TO::to_head: Prev = &Head;	break;
	case List::TO::to_tail: Prev = Tail.pPrev; break;
		//default: std::cout<<"Err" <<std::endl; break;
	}

	if (Prev)
	{
		new Node(Prev, shape);
		m_size++;
	}
}

bool List::RemoveOne(const Shape& desired)
{
	Node* p = Head.pNext;
	while (p != &Tail)
	{
		if (desired == *p->m_Data)//find data
		{
			//if match - delete data, return true
			m_size--;
			delete p;
			return true;
		}
		//delete data, return true
		//else return false
		p = p->pNext;
	}
	return false;
}

int List::Remove_all_match(const Shape& desired)
{
	static int deleted = 0;
	if (RemoveOne(desired))
	{
		deleted++;
		Remove_all_match(desired);
	}
	return deleted;
}

void List::Remove_list()
{
	while (Head.pNext != &Tail)
	{
		delete Head.pNext;
	}
	m_size = 0;
}

void List::Swap(Node* replaceable, Node* movable)
{
	if (replaceable == movable)return;

	if (replaceable->pNext == movable || replaceable->pPrev == movable)
	{		
		Node* binding_tmp = replaceable->pPrev->pNext;
		replaceable->pPrev->pNext = movable->pNext->pPrev;
		movable->pNext->pPrev = binding_tmp;
				
		if (replaceable->pPrev == movable)
		{
			movable->pNext = replaceable->pNext;
			replaceable->pNext = movable;

			replaceable->pPrev = movable->pPrev;
			movable->pPrev = replaceable;
			return;
		}

		replaceable->pNext = movable->pNext;
		movable->pNext = replaceable;
		
		movable->pPrev = replaceable->pPrev;
		replaceable->pPrev = movable;
		return;
	}
	
	if (replaceable != &Tail &&
		replaceable != &Head &&
		movable != &Tail &&
		movable != &Head)
	{
		Node* tmpNext = replaceable->pNext;
		Node* tmpPrev = replaceable->pPrev;
		Node* binding_pNext = replaceable->pNext->pPrev;
		Node* binding_pPrev = replaceable->pPrev->pNext;
				
		replaceable->pNext->pPrev = movable->pNext->pPrev;
		replaceable->pPrev->pNext = movable->pPrev->pNext;
		movable->pNext->pPrev = binding_pNext;
		movable->pPrev->pNext = binding_pPrev;

		replaceable->pNext = movable->pNext;
		replaceable->pPrev = movable->pPrev;
		movable->pNext = tmpNext;
		movable->pPrev = tmpPrev;		
	}	
}

void List::Sort_list(Sorting to)
{
	if (m_size <= 1) { return; }
	/*Node* left_node = Head.pNext;*/
	Node* min_node = Head.pNext;
		
	for (Node* left_node = Head.pNext; left_node->pNext != &Tail; left_node = left_node->pNext)
	{
		double min = left_node->Get_Meth(to);
		
		bool fl = false;//������ - ���� �� ���� �� ���� ������������

		for (Node* current = left_node->pNext; current != &Tail; current = current->pNext)
		{
			double cur = current->Get_Meth(to);
			if (min > cur)
			{
				min = cur;
				min_node = current;
				fl = true;
			}			
		}		
		if (fl) { Swap(left_node, min_node); left_node = min_node; }
		/*else { break; }*/
	}	
}

List& List::operator=(const List& other)
{
	const Node* pOther_Head = &other.Head;
	Node* pOther = pOther_Head->pNext;
	Node* pThis = &Head;

	if (m_size == other.m_size || m_size > other.m_size)
	{
		while (pOther != &other.Tail)
		{
			pThis = pThis->pNext;
			(*pThis).Copy_Data(*pOther);
			pOther = pOther->pNext;
		}
		if (m_size > other.m_size)
		{
			pThis = pThis->pNext;

			while (pThis != &Tail)
			{
				Node* removable = pThis;
				pThis = pThis->pNext;
				delete removable;
			}
			m_size = other.m_size;
		}
	}
	if (m_size < other.m_size)
	{
		while (pThis->pNext != &Tail)
		{
			pThis = pThis->pNext;
			(*pThis).Copy_Data(*pOther);
			pOther = pOther->pNext;
		}

		while (pOther != &other.Tail)
		{
			pThis = new Node(pThis, *(pOther->m_Data));
			pOther = pOther->pNext;
		}
		m_size = other.m_size;
	}

	return *this;
}

List& List::operator=(List&& other)
{
	if (other.m_size)
	{
		if (m_size)
		{this->Remove_list();}

		Head.pNext = other.Head.pNext;
		Tail.pPrev = other.Tail.pPrev;

		Head.pNext->pPrev = &Head;
		Tail.pPrev->pNext = &Tail;
		m_size = other.m_size;

		other.Head.pNext = &other.Tail;
		other.Tail.pPrev = &other.Head;
		other.m_size = 0;
	}
	else
	{
		if (m_size != other.m_size)
		{
			this->Remove_list();
		}
	}

	return *this;
}

std::ostream& operator<<(std::ostream& os, const List& list)
{
	os << "Size_of_list: " << list.m_size<<"\n";
	//Head.pNext - & 1 element
	//1 el.pNext - & Next el
	//if pNext ==nulptr - we are in Tail
	if (!list.m_size)
	{
		os << "Empty list";
	}
	else
	{
		Node* p = list.Head.pNext;
		while (p != &list.Tail)
		{
			os << *p << std::endl;// list.Head.pNext;
			p = p->pNext;
		}
	}

	os << "\n";
	return os;
}

List& operator>>(std::ifstream& file, List& list)
{
	size_t tmp_size;
	////������� ���������
	char  buff[20];
		
	//file.getline(buff, 15) >> list.m_size; //why it is don't work?
	file >> buff >> tmp_size;

	for (size_t i = 0; i < tmp_size; i++)
	{
		file >> buff;
		const char* pbuff = buff;
		if (!strcmp (pbuff, "Rect:")) 
		{ Rect tmp_rect; 
		file >> tmp_rect; 
		list.Ad_to(List::TO::to_tail, tmp_rect);}

		if (!strcmp(pbuff, "Circle:"))
		{Circle tmp_circ; 
		file >> tmp_circ;
		list.Ad_to(List::TO::to_tail, tmp_circ); }
	
	}
	return list;	
}

//bool compArea(const Shape* thirst, const Shape* second)
//{
//	return thirst->Get_area() < second->Get_area();
//}
//
//bool compColor(const Shape* thirst, const Shape* second)
//{
//	return thirst->Get_colour() < second->Get_colour();
//}
//
//bool compDistance(const Shape* thirst, const Shape* second)
//{
//	return thirst->Get_distance() < second->Get_distance();
//}

